package com.alipay.sofa.award.endpoint.impl;

import com.alibaba.common.lang.StringUtil;
import com.alipay.sofa.award.biz.service.enums.AwardEnums;
import com.alipay.sofa.award.biz.service.facade.ActivityAwardFacade;
import com.alipay.sofa.award.biz.service.facade.MqPublishRecordFacade;
import com.alipay.sofa.award.biz.service.facade.UserVisitRecordFacade;
import com.alipay.sofa.award.common.dal.dataobject.Award;
import com.alipay.sofa.award.common.dal.dataobject.UserInfo;
import com.alipay.sofa.award.common.utils.AwardUtils;
import com.alipay.sofa.award.common.utils.DateFormatUtils;
import com.alipay.sofa.award.endpoint.exception.ActivityAwardErrorCodeDescImpl;
import com.alipay.sofa.award.endpoint.exception.ActivityTimeErrorCodeDescImpl;
import com.alipay.sofa.award.endpoint.exception.CommonException;
import com.alipay.sofa.award.endpoint.facade.ActivityAwardRestFacade;
import com.alipay.sofa.award.endpoint.holder.AlipayMiniProgramUserHolder;
import com.alipay.sofa.award.endpoint.response.RestSampleFacadeResp;
import com.alipay.sofa.award.record.common.dal.dataobject.AwardRecord;
import com.alipay.sofa.award.record.facade.AwardRecordFacade;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * ActivityAwardRestImpl
 *
 * @author yangguanchao
 * @since 2018/08/28
 */
public class ActivityAwardRestImpl implements ActivityAwardRestFacade {

    private Random                randomAward = new Random();

    @Autowired
    private ActivityAwardFacade   activityAwardFacade;

    @Autowired
    private MqPublishRecordFacade mqPublishRecordFacade;

    @Autowired
    private AwardRecordFacade     awardRecordFacade;

    @Autowired
    private UserVisitRecordFacade userVisitRecordFacade;

    @Override
    public RestSampleFacadeResp<Map<String, Object>> getAward(String userId, String activityTime)
                                                                                                 throws Exception {
        //try to win the Lottery
        if (StringUtil.isBlank(activityTime)) {
            throw new CommonException(ActivityTimeErrorCodeDescImpl.ACTIVITY_TIME_ERROR_CODE_DESC);
        }
        UserInfo userInfo = this.getUserInfo();
        if (!this.isAwardQualification(true, userInfo, activityTime)) {
            throw new CommonException(ActivityAwardErrorCodeDescImpl.ACTIVITY_AWARD_NOTHING,
                activityTime);
        }
        //limit traffic
        if (!this.canGetAward()) {
            throw new CommonException(ActivityAwardErrorCodeDescImpl.ACTIVITY_AWARD_NOTHING,
                activityTime);
        }
        //check user
        AwardRecord awardRecord = this.getAwardRecordByUser(userInfo);
        Award award = this.tryWinLottery(userId, activityTime);
        if (award == null) {
            throw new CommonException(ActivityAwardErrorCodeDescImpl.ACTIVITY_AWARD_NOTHING,
                activityTime);
        }
        Map<String, Object> data = new HashMap<>();
        //String award code
        String awardCode = AwardUtils.getAwardCode();
        //awardTime
        Date awardTimeDate = new Date();
        //award record
        this.fillAwardRecord(awardRecord, awardCode, awardTimeDate, award);
        //publish msg
        this.mqPublishRecordFacade.publishAwardRecord(awardRecord);

        //result return
        data.put("activityTime", activityTime);
        data.put("awardCode", awardCode);
        String awardTime = DateFormatUtils.parseDate(awardTimeDate);
        data.put("awardTime", awardTime);
        data.put("awardDeadlineTime", DateFormatUtils.parseDate(DateFormatUtils.getEndTime()));
        data.put("awardContent", award.getAwardContent());
        data.put("awardDesc", award.getAwardDesc());
        return new RestSampleFacadeResp<Map<String, Object>>(data);
    }

    @Override
    public RestSampleFacadeResp<Void> getAwardQualification(String userId, String activityTime)
                                                                                               throws Exception {
        if (StringUtil.isBlank(activityTime)) {
            throw new CommonException(ActivityTimeErrorCodeDescImpl.ACTIVITY_TIME_ERROR_CODE_DESC);
        }
        RestSampleFacadeResp<Void> restSampleFacadeResp = new RestSampleFacadeResp<Void>();
        if (this.isAwardQualification(false, this.getUserInfo(), activityTime)) {
            restSampleFacadeResp.setSuccess(true);
        } else {
            restSampleFacadeResp.setSuccess(false);
        }
        return restSampleFacadeResp;
    }

    private boolean isAwardQualification(boolean isStored, UserInfo userInfo, String activityTime) {
        if (this.userVisitRecordFacade.userVisitedOnActivityTime(isStored, userInfo, activityTime)) {
            //has visited
            return false;
        }
        return this.awardRecordFacade.isAwardQualification(activityTime, userInfo.getUserId());
    }

    private boolean canGetAward() {
        //[0,10)
        int value = this.randomAward.nextInt(10);
        return value > 0;
    }

    private UserInfo getUserInfo() throws CommonException {
        UserInfo userInfo = AlipayMiniProgramUserHolder.getUserInfo();
        if (userInfo == null) {
            throw new CommonException(
                ActivityAwardErrorCodeDescImpl.ACTIVITY_AWARD_LOGIN_AUTH_ERROR);
        }
        return userInfo;
    }

    private AwardRecord getAwardRecordByUser(UserInfo userInfo) throws Exception {
        AwardRecord awardRecord = new AwardRecord();
        //userId
        awardRecord.setUserId(userInfo.getUserId());
        //nick name
        awardRecord.setNickName(userInfo.getNickName());
        //picture
        awardRecord.setAvatar(userInfo.getAvatar());
        return awardRecord;
    }

    private void fillAwardRecord(AwardRecord awardRecord, String awardCode, Date awardTimeDate,
                                 Award award) throws Exception {
        awardRecord.setAwardCode(awardCode);
        this.convertAwardToRecord(awardRecord, award);
        awardRecord.setAwardTime(awardTimeDate);
        //awardDeadlineTime
        awardRecord.setAwardDeadlineTime(DateFormatUtils.getEndTime());
    }

    private void convertAwardToRecord(AwardRecord awardRecord, Award award) {
        awardRecord.setActivityTime(award.getActivityTime());
        awardRecord.setRank(award.getRank());
        awardRecord.setAwardContent(award.getAwardContent());
        awardRecord.setAwardDesc(award.getAwardDesc());
    }

    private Award tryWinLottery(String userId, String activityTime) {
        for (AwardEnums awardEnums : AwardEnums.values()) {
            //rank 4/3/2/1
            String awardRank = awardEnums.getRank();
            Award award = this.getAward(userId, activityTime, awardRank);
            if (award != null) {
                //win the lottery
                return award;
            }
        }
        return null;
    }

    private Award getAward(String userId, String activityTime, String rank) {
        return this.activityAwardFacade.tryWinLottery(userId, activityTime, rank);
    }
}
